<?php
###############   COPYLEFT GPLv3 LICENSE   ###############
##
## JFX Version 0.2.9
## Website Management Software
## www.jfxcms.com
##
## Copyright 2009 GPLv3 - http://www.opensource.org/licenses/gpl-3.0.html
##
## Anthony Gallon
## oi_antz@hotmail.com
##
## Permission is hereby granted to any person having a copy of this software
## to freely use and modify as required so long as the copyright notices
## and branding remain intact.
##
## Full license details available at http://www.jfxcms.com/license
##
###############   COPYLEFT GPLv3 LICENSE   ###############

global $IUsers_FloodCheck;
require_once('IUsers_User.class.php');


class JFX_Module_Iusers extends JFX_Module
{
public $keyname = 'iusers';
public $title = 'Instant User Management';
public $version = '0.1.1';
public $hasLoggedPageRequest = false;
protected $log = null;
protected $ContentEditAlias = '';
protected $IUsers_Config = array();

/**
 * API method to check if user belongs to a group or any of a number of groups
 * Accepts:
 * group key as string or group keys as array of group strings
 * optional userid as int, if not supplied, takes from $USER->userid
 */
public function isMemberOfGroup($groupKey, $userid=''){
	$USER = JFX::registry('IUsers_User');
	$DB = JFX::registry('db');
	$userid = (int) $userid;

	if(is_array($groupKey)){
		foreach($groupKey as $k=>$group){
			if($this->isMemberOfGroup($group, $userid)) return true;
		};
		// not found
		return false;
	};

	// testing for a single group as string
	$groupKey = preg_replace('/[^a-zA-Z0-9\-_]/', '', $groupKey);
	if($userid==0) $userid = (int) $USER->userid;
	if($DB->countRows($CONFIG->dbprefix.'iusers_to_groups', "user_id = '{$userid}' AND group_key = '{$groupKey}'")>0) return true;
	else return false;
}


public function getPageActionButtons($blockId, $pageid){
    $CONFIG = JFX::registry('config');

	$button = new JFX_Page_Button;
	$button->imageUrl = $CONFIG->imageUrl.'/admin/icons/key-gold.png';
	$button->alternativeText = $this->lang('set_access_permissions');
	$button->title = $this->lang('set_access_permissions');
	$button->moduleName = $this->keyname;
	$button->moduleMethod = 'setPagePermissions';
	$button->pageId = $pageid;
	$button->id = $blockId;
	$button->blockId = $blockId;

    $returnButtons = array($button);

	return $returnButtons;
}




public function getBlockActionButtons($blockid, $pageid=''){
    $CONFIG = JFX::registry('config');
	
    $button1 = new JFX_Block_Button;
	$button1->pageId = $pageid;
    $button1->alternativeText = $this->lang('set_access_permissions');
    $button1->moduleName = 'iusers';
    $button1->moduleMethod = 'setBlockPermissions';
    $button1->imageUrl = $CONFIG->imageUrl.'/admin/icons/key-gold.png';
    $button1->title = $this->lang('set_access_permissions');
    $button1->blockId = $blockid;
    $returnButtons = array($button1);

	$block = new JFX_Block;
	$block->loadById($blockid, $pageid);

	if($block->moduleKey=='iusers'){
		// for iusers content types

		switch($block->moduleAction){
			case 'loginform':
				$button2 = new JFX_Block_Button;
				$button2->pageId = $pageid;
				$button2->alternativeText = $this->lang('set_login_parameters');
				$button2->moduleName = 'iusers';
				$button2->moduleMethod = 'setLoginParameters';
				$button2->imageUrl = $CONFIG->imageUrl.'/admin/icons/key-gold.png';
				$button2->title = $this->lang('set_login_parameters');
				$button2->blockId = $blockid;
				$returnButtons[] = $button2;
			break;
			case 'registerform':

			break;
		}

	}

	return $returnButtons;
}



public function setPagePermissions($page){
    $blockDetails = $page->getDetails();
    require($this->dirname.'/actions/set-page-permissions.php');
}



public function setBlockPermissions($block){
    $blockDetails = $block->getDetails();
    require($this->dirname.'/actions/set-block-permissions.php');
}

public function setLoginParameters($block){
    $blockDetails = $block->getDetails();
    require($this->dirname.'/actions/set-login-parameters.php');
}


public function prepare($details){
    return $this->getContent($details);
}

/**
 * API method to load user data
 * Returns data from iusers tab combined with data from other modules
 * Accepts: $userid (int)
 * Returns: array
 */
public function getUserData($userid){
  $DB = JFX::registry('db');
  $userid = (int) $userid;
  $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE id = '{$userid}'");
  $eParams = array('userid'=>$userid, 'uData'=>$uData);
  JFX::hook('JFX_Module_Iusers.getUserData', $eParams);
  $uData = $eParams['uData'];
  unset($newData);
  return $uData;
}

public function getUser(){
	return JFX::registry('IUsers_User');
}

/**
 *  Allows any code to register a new user in the database
 *  Accepts an array of user data, with keys "username" and "email" being mandatory, "password" is optional
 *  All values must be unencrypted
 *  Returns the new user id on success or an array on error:
 *  array(
 *      'error' => true,
 *      'errors' => array('Message 1', 'Message 2', 'etc')
 *  )
 */
public function RegisterUser($uData){
    $DB = JFX::registry('db');
    $CRYPT = JFX::registry('JFX_Crypt');

    $error = false;
    $errors = array();

    // check a few things first
    if(!isset($uData['username'])){
        $error = true;
        $errors[] = $this->Lang('invalid_username');
    }

    if(!isset($uData['email'])){
        $error = true;
        $errors[] = $this->Lang('invalid_email');
    }


    if(!JFX_Filter::checkEmail($uData['email'])){
        $error = true;
        $errors[] = $this->Lang('invalid_email');
    }

    if($DB->countRows($CONFIG->dbprefix.'iusers', "username = '{$username}'")>0){
        $error = true;
        $errors[] = $this->Lang('username_already_registered');
    }

    $emailMD5 = md5(strtolower($uData['email']));

    if($DB->countRows($CONFIG->dbprefix.'iusers', "email_md5 = '{$emailMD5}'")>0){
        $error = true;
        $errors[] = $this->Lang('email_already_registered');
    }

    if($error){
        return array('error'=>true, 'errors'=>$errors);
    }

    $uData['email_crypt'] = isset($uData['email']) ? $CRYPT->crypt($uData['email']) : '';
    $uData['email_md5'] = $emailMD5;
    $uData['pass'] = isset($uData['password']) ? $CRYPT->crypt($uData['password']) : '';

    // create a compliant array to insert
    $newUData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE id = 1");

    unset($newUData['id']);

    foreach($newUData as $k=>$v){
        $newUData[$k] = isset($uData[$k]) ? $uData[$k] : '';
    }
    
    $userid = $DB->insert($CONFIG->dbprefix.'iusers', $newUData);

    // groups
    if(!is_array($uData['groups'])){
        $uData['groups'] = explode(',', $uData['groups']);
    };
    foreach($uData['groups'] as $k=>$groupKey){
        $groupKey = preg_replace('/[^a-zA-Z0-9\-_]/', '', $groupKey);
        if($DB->countRows($CONFIG->dbprefix.'iusers_groups', "keyname = '{$groupKey}'")==0){
            unset($uData['groups'][$k]);
        };
    };
    if(count($uData['groups'])==0){
        $uData['groups'] = explode(',', $this->GetConfig('default_groups_for_self_registration'));
    };
    foreach($uData['groups'] as $groupKey){
        $dbParams = array(
            'user_id' => $userid,
            'group_key' => $groupKey
        );
        $DB->insert($CONFIG->dbprefix.'iusers_to_groups', $dbParams);
    };
    
    return $userid;
}




/**
 * Allows any code to log a user in by passing either userid, username, email or user data in an array
 */
public function Login($data){
    $USER = JFX::registry('IUsers_User');
    $DB = JFX::registry('db');


    if(is_array($data)){
        return $USER->login($data);
    }
    if(JFX_Filter::checkEmail($data)){
        $emailMD5 = md5(strtolower($data));
        $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE email_md5 = '{$emailMD5}'");
        return $USER->login($uData);
    }
    if(intval($data) === $data && $data > 0){
        $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE id = '{$data}'");
        return $USER->login($uData);
    }
    $data = preg_replace('/[^a-zA-Z0-9\-_]/', '', $data);
    $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE username = '{$data}'");
    if(is_array($uData)){
        return $USER->login($uData);
    }

    // failed to login :(
    return false;

}



public function __construct(){
    parent::__construct();

    if(!JFX_Module::isInstalled('iusers')) return;

	$this->title = $this->lang('module_title');

    
    // automatically load our configuration settings once only
    if(count($this->IUsers_Config) == 0) $this->LoadConfig();
    if(count($this->IUsers_Config) == 0){
        // probably not installed, can't proceed
        return;
    };
    $USER = IUsers_User::startSession();
    JFX::register('IUsers_User', $USER);

	$dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
	$this->dirname = $dirname;
    //$USER = JFX::registry('IUsers_User');
    $SMARTY = JFX::registry('Smarty');
    $DB = JFX::registry('db');
    // check for dos attacks/flooding
    global $IUsers_FloodCheck;
    if($IUsers_FloodCheck !== 'served'){
        $IUsers_FloodCheck = 'served';
        if(!is_array($USER->floodCheck) || count($USER->floodCheck)==0) $USER->floodCheck = array('numRequests'=>0, 'lastCheck'=>time());
        $USER->floodCheck['numRequests']++;
        if($USER->floodCheck['lastCheck'] < (time()-$this->GetConfig('dos_frequency'))){
            // reset the records every x seconds
            $USER->floodCheck['numRequests'] = 0;
            $USER->floodCheck['lastCheck'] = time();
        };
        if($USER->floodCheck['numRequests'] > $this->GetConfig('dos_max')){
            // flooding occurs!
            while(ob_get_level()>0) ob_end_clean();
            header('Status: '.$this->GetConfig('dos_status'));
            die($this->ProcessTemplate('dos_response.php'));
        };
    };
    if(!$USER->isLoggedIn()){
        // check if they have an auto-login cookie
        if(isset($_COOKIE[$this->GetConfig('cookie_name').'_userid']) && $_COOKIE[$this->GetConfig('cookie_name').'_userid']>0){
            // they have a cookie set, lets see if it is valid
            $userid = (int) $_COOKIE[$this->GetConfig('cookie_name').'_userid'];
            $hashCookie = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE[$this->GetConfig('cookie_name').'_hash']);
            if($DB->countRows($CONFIG->dbprefix.'iusers', "id = '{$userid}' AND cookie_hash = '{$hashCookie}'")>0){
                // valid returning user
                $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE id = '{$userid}'");
                $USER->login($uData);
            }else{
                // they have a cookie, but not the right authorization, maybe a security risk?
                $CRYPT = JFX::registry('JFX_Crypt');
                try{
                    $uData = $DB->fetchRow("SELECT * FROM {$CONFIG->dbprefix}iusers WHERE id = '{$userid}'");
                    $uData['email'] = $CRYPT->decrypt($uData['email_crypt']);
                    throw new exception('A user has a cookie set, but the cookie hash is not valid. Maybe a hack attempt? '."\nThey provided a userid corresponding to the following result set: \n".print_r($uData, true));
                }catch (exception $e){
                    $msg = $e->getMessage()."\n\nUrl: ".THIS_PAGE_URL."\n\n".print_r($_SERVER, true)."\n\n".print_r($_SESSION, true)."\n\n".print_r($_COOKIE, true)."\n\n".print_r($_POST, true);
                    $subject = $this->Lang('invalid_cookie_set_admin_notice');
                    $toFrom = array(
                        'toEmail' => $this->GetConfig('admin_notification_alerts'),
                        'toName'=>''
                    );
                    JFX_Email::sendRaw($subject, $msg, $toFrom);
                };
                // remove these cookies, since they are such a nuisance...
                setcookie ($this->GetConfig('cookie_name').'_userid', "", (time() - (60*60*24*100)));
                setcookie ($this->GetConfig('cookie_name').'_hash', "", (time() - (60*60*24*100)));
                //JFX::addError('LOL!! Your cookies were corrupt!!');
            };
        };
    }





    // only log once per page
    if(!$this->hasLoggedPageRequest){

        $USER = JFX::registry('IUsers_User');
        $CONFIG = JFX::registry('config');

        $this->hasLoggedPageRequest = true;

        $sId = session_id();

        $serverData = '';
        $sessionData = '';
        $postData = '';
        $getData = '';

        // if configured in control panel, you can log every page's session object
        if($this->GetConfig('monitor_session_data')) $sessionData = serialize($_SESSION);

        if($DB->countRows($CONFIG->dbprefix.'iusers_history', "session_id = '{$sId}'") == 0) $sessionData = serialize($_SESSION);

        if($this->GetConfig('monitor_server_data')) $serverData = serialize($_SERVER);

        if($this->GetConfig('monitor_post_data')) $postData = serialize($_POST);

        if($this->GetConfig('monitor_get_data')) $getData = serialize($_GET);




        $uHistory = array(
            'userid' => $USER->userid,
            'username' => $USER->username,
            'tstamp' => time(),
            'session_id' => session_id(),
            'url' => THIS_PAGE_URL,
            'session_data' => $sessionData,
            'server_data' => $serverData,
            'get_data' => $getData,
            'post_data' => $postData
        );

        $DB->insert($CONFIG->dbprefix.'iusers_history', $uHistory);

    }



    // register the checkperms block function for smarty
    $SMARTY->register_block('showif', array($this, 'showif_block'));
    $SMARTY->register_block('showto', array($this, 'showif_block'));
    $SMARTY->register_block('hidefrom', array($this, 'hidefrom_block'));

    JFX::register('IUsers', $this);

    $this->SetSmartyVars();

}




public function SetSmartyVars(){
    // now we assign some variables for use in smarty
    $USER = JFX::registry('IUsers_User');
    $SMARTY = JFX::registry('Smarty');
    $iusers = array(
        'username' => $USER->username,
        'userid' => $USER->userid,
        'isLoggedIn' => $USER->isLoggedIn(),
        'country' => $USER->country
    );
    $SMARTY->assign('IUsers', $iusers);
}


public function showif_block($params, $content, &$smarty){
    $USER=JFX::registry('user');
    $DB = JFX::registry('db');
    global $gCms;

    if (!array_key_exists('groups', $params)) {
        $SMARTY->trigger_error("assign: missing 'groups' parameter");
        return;
    };

    $groups = explode(',', $params['groups']);
    foreach($groups as $k=>$v){
        $groups[$k] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $v);
        if($groups[$k]=='') unset($groups[$k]);
    };

    if(count($groups)==0){
        $SMARTY->trigger_error('At least one group must be defined in the groups attribute');
        return;
    };

    foreach($groups as $k=>$v){
        $where = "group_key = '{$v}' AND user_id = '{$USER->userid}'";
        if($DB->countRows($CONFIG->dbprefix.'iusers_to_groups', $where) > 0) return $content;
    };
    // not permitted
    return '';

}



public function hidefrom_block($params, $content, &$smarty){
    $USER=JFX::registry('user');
    $DB = JFX::registry('db');
    global $gCms;

    if (!array_key_exists('groups', $params)) {
        $SMARTY->trigger_error("assign: missing 'groups' parameter");
        return;
    };

    $groups = explode(',', $params['groups']);
    foreach($groups as $k=>$v){
        $groups[$k] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $v);
        if($groups[$k]=='') unset($groups[$k]);
    };

    if(count($groups)==0){
        $SMARTY->trigger_error('At least one group must be defined in the groups attribute');
        return;
    };

    foreach($groups as $k=>$v){
        $where = "group_key = '{$v}' AND user_id = '{$USER->userid}'";
        if($DB->countRows($CONFIG->dbprefix.'iusers_to_groups', $where) > 0) return '';
    };

    // permitted
    return $content;

}




function admin($url, $dirname){

        // get hold of our objects
        $DB = JFX::registry('db');
        $SMARTY = JFX::registry('Smarty');
        $USER = JFX::registry('IUsers_User');
        $JFXUSER = JFX::registry('JFX_User');
        $CRYPT = JFX::registry('JFX_Crypt');
        $CONFIG = JFX::registry('config');
        $VIEW = JFX::registry('JFX_View');
        $LANG = JFX::registry('lang');
        
        $request = trim(str_replace($url, '', THIS_PAGE_URL), '/');
        $request = str_replace('../', '', $request);
        $request = explode('?', $request);
        $request = explode('/', trim($request[0], '/'));
        $activeTab = array_shift($request);

        // enable us to insert error messages on the page
        $this->addJsLink('places.js');
        $this->addJsLink('admin.js');
        $this->addJsLink('AntzBase.js');
        $this->addStylesheet('backend.css');

        // configuration may allow admin to register accounts without a name
        $insistFirstName = $this->GetConfig('be_insist_fname');
        $insistLastName = $this->GetConfig('be_insist_lname');

        if(file_exists($dirname.'/tabs/admin.'.$activeTab.'.php') && $this->checkPermission('perm_'.$activeTab)) $selectedTab = $activeTab;
        else $selectedTab = 'view';

        $tabs = array();

        if($this->checkPermission('perm_users')){
            // tabs for managing users
            $tabs['view'] = $this->Lang('view_tab');
            $tabs['new'] = $this->Lang('new_tab');
            $tabs['edit'] = $this->Lang('edit_tab');
        };
        if($this->checkPermission('perm_groups')){
            $tabs['groups'] = $this->Lang('groups_tab');
        };
        if($this->checkPermission('perm_places')){
            $tabs['places'] = $this->Lang('places_tab');
        };
        if($this->checkPermission('perm_config')){
            $tabs['config'] = $this->Lang('config_tab');
        };


        $actionUrls = array();

        // calculate the urls to get to each tab
        foreach($tabs as $tab=>$title){
            $params['active_tab'] = $tab;
            $actionUrls[$tab] = $url.'/'.$tab;
        };

        $SMARTY->assign('actionUrls', $actionUrls);

        $adminTabs = array();
        foreach($tabs as $k=>$title){
            if($k==$selectedTab) $class = 'selected';
            else $class = '';
            $adminTabs[] = array(
                'key'=>$k,
                'title' => $title,
                'url' => $actionUrls[$k],
                'class' => $class
            );
        };
        $SMARTY->assign('adminTabs', $adminTabs);

        echo $this->fetchTemplate('admin.tabs.php');

        echo '<div id="admin-content">';
        include($dirname.'/tabs/admin.'.$selectedTab.'.php');
        echo '</div>';


}


/**
 *  Public action server, requests coming to /modules/iusers/* will come through this method
 * @param string $request
 */
function serve($request){
    $CONFIG = JFX::registry('config');
    $DB = JFX::registry('db');
    $CRYPT = JFX::registry('JFX_Crypt');
    $USER = JFX::registry('IUsers_User');
    
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__)).'/ajax';
    $request = explode('?', $request);
    $requestedFile = str_replace('../', '', rtrim($request[0], '/'));
    if(file_exists($dirname.'/'.$requestedFile.'.php')) include($dirname.'/'.$requestedFile.'.php');

}




function updateSettings($params){
    /*echo '<pre>';
    var_dump($params);
    echo '</pre>';*/
}




function getBlockActions(){
    //$USER = JFX::registry('user');
    $actions = array();
    if($this->checkPermission('perm_login')){
        $actions[] = array(
            'keyname' => 'loginform',
            'title' => $this->lang('login_form'),
            'desc' => ''
        );
    };
    if($this->checkPermission('perm_register')){
        $actions[] = array(
            'keyname' => 'registerform',
            'title' => 'register_form',
            'desc' => ''
        );
    };
    if($this->checkPermission('perm_lostpass')){
        $actions[] = array(
            'keyname' => 'lostpassform',
            'title' => 'lost_password_form',
            'desc' => ''
        );
    };

    return $actions;
}




function getDefaultContent($action){
    // get hold of our objects
    $DB = JFX::registry('db');
    $SMARTY = JFX::registry('Smarty');
    $USER = JFX::registry('IUsers_User');
    $JFXUSER = JFX::registry('JFX_User');
    $CRYPT = JFX::registry('JFX_Crypt');
    $CONFIG = JFX::registry('config');
    $VIEW = JFX::registry('JFX_View');
    $LANG = JFX::registry('lang');


    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
    ob_start();

    switch($action){
        case 'loginform':
            include($dirname.'/actions/login.php');
        break;
        case 'registerform':
            include($dirname.'/actions/register.php');
        break;
    }

    $content = ob_get_contents();
    ob_end_clean();
    return $content;
}

function getContent($params){

    $DB = JFX::registry('db');
    $CONFIG = JFX::registry('config');
    $LANG = JFX::registry('lang');
    $CRYPT = JFX::registry('JFX_Crypt');
    $USER = JFX::registry('IUsers_User');

    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
    ob_start();

    switch($params['module_action']){
        case 'loginform':
            include($dirname.'/actions/login.php');
        break;
        case 'registerform':
			
            include($dirname.'/actions/register.php');
        break;

    }




    $content = ob_get_contents();
    ob_end_clean();
    return $content;

}


public function hook($hook, &$params){
    $VIEW = JFX::registry('JFX_View');
    $DB = JFX::registry('db');
    $CONFIG = JFX::registry('config');
    $USER = JFX::registry('IUsers_User');

    parent::hook($hook, $params);
}


function getToolbarButtons($pageid){

    $buttons = array();
    $buttons[] = array(
        'image' => 'access.png',
        'title' => $this->lang('set_page_access_permissions'),
        'alt' => 'Permissions',
        'id' => 'IUsersPagePermissions',
        'click' => '
                var href = "'.$this->adminUrl.'/set-page-permissions/?page='.$pageid.'&KeepThis=true&TB_iframe=true&height=500&width=700";
                tb_show("'.$this->lang('set_page_access_permissions').'", href, false);'
    );

    return $buttons;
}


function DoAction($action, $url='', $dirname=''){
    
    $DB = JFX::registry('db');


    // get hold of our objects
    $SMARTY = JFX::registry('Smarty');
    $USER = JFX::registry('IUsers_User');
    $CRYPT = JFX::registry('JFX_Crypt');
    $CONFIG = JFX::registry('config');
    $VIEW = JFX::registry('JFX_View');
    $LANG = JFX::registry('lang');
    
    $this->IUsers2SMF = JFX::registry('JFX_Module_Iusers2smf');
    $rootPath = str_replace(DIRECTORY_SEPARATOR, '/', $CONFIG->baseDir);


    // we can set any usernames that are disallowed - must be lowercase
    $DISALLOWED_USERNAMES = array(
        'admin',
        'guest',
        'antz',
        'oi_antz',
        'oi-antz'
    );

    $emailVerificationUrl = JFX::getUrlById($this->GetConfig('email_verification_id'));


    if($action == 'decrypt'){
        echo $CRYPT->decrypt($params['value']);
        return;
    }elseif($action=='country_title'){
        $id = preg_replace('/[^a-zA-Z0-9]/', '', $params['id']);
        echo $DB->oneValue($CONFIG->dbprefix.'iusers_countries', 'title', "id = '{$id}'");
        return;
    }else if($action=='city_title'){
        $id = (int) $params['id'];
        echo $DB->oneValue($CONFIG->dbprefix.'iusers_cities', 'title', "id = '{$id}'");
        return;


    /**
     *  CHECK PERMISSIONS, REDIRECT ON FAIL
     */
    }else if($action=='checkperms_redirect'){
        // check if they have permission to view this page, if not, set last page and redirect to the login page
        
        $loginUrl = JFX::GetUrlById($this->GetConfig('login_id'));
        $logoutUrl = JFX::GetUrlById($this->GetConfig('logout_id'));

        if(THIS_PAGE_URL == $CONFIG->baseUrl){
            // always permitted to view the homepage
            return;
        };
        if(strpos(THIS_PAGE_URL, $logoutUrl)!==false){
            // always permitted to view the logout page
            return;
        };
        if(strpos(THIS_PAGE_URL, $loginUrl)!==false){
            // always permitted to view the login page
            return;
        };

        // for module ELetters
        if($ELetters = $this->GetModuleInstance('ELetters')){
            // allow access to the page if a newsletter is being sent
            if($ELetters->isSending()) return;
        };

        if(isset($USER->redirhash) && $CRYPT->decrypt(get('redirhash')) == $USER->redirhash){
            // this is definitely the login page, we must allow them to see it even if the system is mis-configured
            unset($USER->redirhash);
            return;

        }else{
            // this is probably not the login page
            $pagesToGroups = $CONFIG->dbprefix.'iusers_pages_to_groups';
            $usersToGroups = $CONFIG->dbprefix.'iusers_to_groups';
            $query = "SELECT
              {$CONFIG->dbprefix}iusers_pages_to_groups.page_id as page_id
              FROM
              {$pagesToGroups} JOIN {$usersToGroups}
              ON
              {$pagesToGroups}.group_key = {$usersToGroups}.group_key
              WHERE
              {$pagesToGroups}.page_id = '{$gCms->variables['content_id']}'
              AND
              {$usersToGroups}.user_id = '{$USER->userid}'";
              $row = $DB->fetchRow($query);

              if(is_array($row) && count($row)>0){
                  // permitted to view
                  return;

              }else{
                  // not permitted, redirect to the login page

                  JFX::setLastPage();
                  $hash = rand(0, 9999);
                  $USER->redirhash = $hash;
                  $loginUrl = JFXAddParamsToUrl($loginUrl, array('redirhash'=>$CRYPT->crypt($hash)));
                  if($USER->isLoggedIn()) {

                      JFX::addError($this->Lang('checkperms_redirect_error', $USER->username));
                  }else{
                      JFX::addError($this->Lang('must_be_logged_in_for_page'));
                  };
                  JFX::redirect($loginUrl);

              };

        };

    /**
     *  SHOW THE FLAGS FOR CHANGING COUNTRY
     */
    }else if($action == 'flags'){
         echo 'Changing country is not available until CMS Made Simple supports languages';
         return;

         $flags = $DB->fetchAll("SELECT id, title, filename FROM {$CONFIG->dbprefix}iusers_countries WHERE show_flag = 1");
         if(!$flags) $flags = array();
         foreach($flags as $k=>$v){
             $flags[$k]['image'] = $CONFIG->baseUrl.'/modules/'.$this->GetName().'/images/flags/'.$v['filename'];
             $urlParams = array('country'=>$v['id'], 'return_url'=>THIS_PAGE_URL);
             $url = JFX::GetUrlByAlias($this->GetConfig('change_country_url'));
             $flags[$k]['url'] = JFX::AddParamsToUrl($url, $urlParams);
             if($v['id']==$USER->country) $flags[$k]['selected'] = true;
             else $flags[$k]['selected'] = false;
         };
         $SMARTY->assign('IUsers_Flags', $flags);
         echo $this->ProcessTemplate('flags.php');


    /**
     *  ALLOW A USER TO CHANGE THEIR COUNTRY
     */
    }else if($action == 'change_country'){
        $country = preg_replace('/[^a-zA-Z0-9]/', '', get('country'));
        $url = get('return_url');
        if(strpos($url, 'http')===false){
            $url = JFX::getLastPage();
        };
        if($DB->countRows($CONFIG->dbprefix.'iusers_countries', "id = '{$country}'")==0){
            JFX::addError($this->lang('invalid_country'));
            JFX::redirect($url);
        }else{
            $USER->country = $country;
            JFX::redirect($url);
        };

    /**
     *  LOGOUT
     */
    }else if($action=='logout'){
         $USER->logout();
         setcookie ($this->GetConfig('cookie_name').'_userid', "", time()-60*60*24*100);
         setcookie ($this->GetConfig('cookie_name').'_hash', "", time()-60*60*24*100);

         JFX::addSuccess($this->lang('logout_success'));

	if(get('return_url')!='') $returnUrl = get('return_url');
        else $returnUrl = JFX::getLastPage();

        // allow other modules to act on logout action
        $eParams = array();
        JFX::hook('JFX_Module_Iusers.logoutProcess', $eParams);

        // SMF integration
        if(is_object($this->IUsers2SMF) && $this->IUsers2SMF instanceof IUsers2SMF){
            $this->IUsers2SMF->logout($returnUrl);
        };// end SMF integration

        // only gets here if smf not enabled
        JFX::redirect($returnUrl);

    /**
     *  DEFAULT
     */
    }else if($action=='default'){

    /**
     *  LOGIN
     */
    }else if($action=='login'){
        include('actions/login.php');
        return;

    /**
     *  REGISTER
     */
    }else if($action=='register'){
        // configuration may allow admin to register accounts without a name
        $insistFirstName = $this->GetConfig('fe_insist_fname');
        $insistLastName = $this->GetConfig('fe_insist_lname');

        include('actions/register.php');


    /**
     *  PROFILE
     */
    }else if($action=='profile'){
        include('actions/profile.php');

     /**
     *  VERIFY EMAIL ADDRESS
     */
    }else if($action=='verify_email'){
        include('actions/verify_email.php');




     /**
     *  LOST PASSWORD RETRIEVAL
     */
    }else if($action=='lost_password'){
        include('actions/lost_password.php');














    /**
     *  DEFAULT ADMIN
     */









    }
}



function ProcessEmailTemplate($tpl, $params, $layoutTpl=''){
    $SMARTY = JFX::registry('Smarty');
	if($layoutTpl == ''){
		$layoutTpl = 'layout.php';
	}
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
    foreach($params as $k=>$v){
    	$SMARTY->assign('IUsers_'.$k, $v);
    }
    $content = $SMARTY->fetch($dirname.'/email_templates/'.$tpl);
    $SMARTY->assign('IUsers_EmailContent', $content);
    return $SMARTY->fetch($dirname.'/email_templates/'.$layoutTpl);
}






function LoadConfig(){
    $DB = JFX::registry('db');
    $CONFIG = JFX::registry('config');
    // make sure we have been installed!
    $config = $DB->fetchAll("SELECT * FROM {$CONFIG->dbprefix}iusers_config");

    if($config === false) return;
    foreach($config as $k=>$v){
        $this->IUsers_Config[$v['k']] = $v['v'];
    };
}







function GetConfig($k){
    if(isset($this->IUsers_Config[$k])) return $this->IUsers_Config[$k];
    else if($this->ThrowConfigExceptions) throw new Exception($this->GetName().'->GetConfig was asked to find a non-existing key: '.$k);
    else return false;
}










function ReadEmailTemplate($name){
    if(!file_exists(dirname(__FILE__).'/email_templates/'.$name)){
        throw new Exception('Email template: modules/'.$this->GetName().'/email_templates/'.$name.' does not exist!');
        return '';
    }else{
        // get our specific template
        $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
        ob_start();
        include($dirname.'/email_templates/'.$name);
        $msg = ob_get_contents();
        ob_end_clean();

        // get our layout template
        ob_start();
        include($dirname.'/email_templates/layout.php');
        $tpl = ob_get_contents();
        ob_end_clean();

        // insert our specific template to the layout template
        $tpl = str_replace(':|content|:', $msg, $tpl);

        return $tpl;
    }
}




/**
 *  INSTALL AND UNINSTALL METHODS
 */

function Install(){
    include('install/install.php');
    $this->resetLanguages();
}
function Uninstall(){
    include('install/uninstall.php');
}

function Upgrade(){
    $DB = JFX::registry('db');
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));


    // add some new configuration options
    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'wrap_form_components'")==0){
        $dbParams = array(
            'k' => 'wrap_form_components',
            'v' => 1,
            'title' => 'Wrap form components in a div with class "component"?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }

    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'auto_forms'")==0){
        $dbParams = array(
            'k' => 'auto_forms',
            'v' => 1,
            'title' => 'Auto-generate forms without using templates?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }

    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'show_labels'")==0){
        $dbParams = array(
            'k' => 'show_labels',
            'v' => 1,
            'title' => 'Show labels in form components?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }


    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'register_show_fields'")==0){
        $dbParams = array(
            'k' => 'register_show_fields',
            'v' => '',
            'title' => 'Which fields to show on registration page?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }

    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'profile_show_fields'")==0){
        $dbParams = array(
            'k' => 'profile_show_fields',
            'v' => '',
            'title' => 'Which fields to show on profile page?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }

    if($DB->countRows($CONFIG->dbprefix.'iusers_config', "k = 'email_login'")==0){
        $dbParams = array(
            'k' => 'email_login',
            'v' => 0,
            'title' => 'Login with email instead of username?',
            'field_type' => 'boolean'
        );
        $DB->insert($CONFIG->dbprefix.'iusers_config', $dbParams);
    }


    // converting from storing aliases to ids
    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('login_url')."'");
    $dbParams = array('k'=>'login_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'login_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('lost_password_url')."'");
    $dbParams = array('k'=>'lost_password_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'lost_password_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('logout_url')."'");
    $dbParams = array('k'=>'logout_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'logout_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('email_verification_url')."'");
    $dbParams = array('k'=>'email_verification_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'email_verification_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('register_url')."'");
    $dbParams = array('k'=>'register_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'register_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('profile_url')."'");
    $dbParams = array('k'=>'profile_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'profile_url'");

    $id = $DB->oneValue($CONFIG->dbprefix.'content', 'content_id', "content_alias = '".$this->GetConfig('tnc_url')."'");
    $dbParams = array('k'=>'tnc_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update($CONFIG->dbprefix.'iusers_config', $dbParams, "k = 'tnc_url'");








    // remove change country until languages are supported
    $DB->delete($CONFIG->dbprefix.'iusers_config', "k = 'change_country_url'");






}


function Restore($tstamp){
    $DB = JFX::registry('db');

    $tables = array(
        'iusers',
        'iusers_groups',
        'iusers_cities',
        'iusers_config',
        'iusers_countries',
        'iusers_to_groups',
        'iusers_pages_to_groups',
        'iusers_history'
    );

    $dirname = dirname(__FILE__);
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);

    $folder = $dirname.'/backups/'.$tstamp;
    if(!is_dir($folder)) return false;

    foreach($tables as $k=>$v){
        // read file contents
        ob_start();
        include($folder.'/'.$v.'.sql');
        $sql = ob_get_contents();
        ob_end_clean();
        $sql = str_replace('prefix_', $CONFIG->dbprefix, $sql);
        $DB->query($sql);
    };

    return true;

}

function Backup(){

    $DB = JFX::registry('db');

    $tables = array(
        'iusers',
        'iusers_groups',
        'iusers_cities',
        'iusers_config',
        'iusers_countries',
        'iusers_to_groups',
        'iusers_pages_to_groups',
        'iusers_history'
    );

    $dirname = dirname(__FILE__);
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);

    $key = time();
    $folder = $dirname.'/backups/'.$key;

    mkdir($folder, 0777);

    $prefix = $CONFIG->dbprefix;

    // create the notice file
    $fh = fopen($folder.'/info.txt', 'w');
    $content = 'Backup created at '.date('H:i d M Y')."\n\nTables in backup: \n";
    foreach($tables as $k=>$v){
        $content .= $prefix.$v."\n";
    };
    fwrite($fh, $content);
    fclose($fh);

    // create the backup sql for each table
    foreach($tables as $k=>$v){
        $q = "SELECT * FROM {$prefix}{$v}";
        $rows = $DB->fetchAll($q);
        $sql = $this->GetSqlRow($v, $rows);
        file_put_contents($folder.'/'.$v.'.sql', $sql);
    };

}

function GetSqlRow($tablename, $rows){
    // get our keys
    $DB = JFX::registry('db');

    $keys = array();
    foreach($rows as $k=>$v){
        foreach($v as $key=>$value){
            $keys[] = $key;
        };
        break;
    };

    // get our values
    $values = array();
    foreach($rows as $k=>$v){
        $values[$k] = array();
        foreach($v as $key=>$value){
            $values[$k][] = $DB->escape($value);
        };
    };

    // create our field definition
    $sql = "INSERT INTO prefix_{$tablename} (`".implode('`, `', $keys)."`) VALUES ";
    foreach($values as $k=>$row){
        $sql .= "('".implode("', '", $row)."'),";
    };
    $sql .= ';';
    if(substr($sql, strlen($sql)-2) == ',;'){
        $sql = substr($sql, 0, strlen($sql)-2).';';
    };
    return $sql;
}




function AddPage($params, $title, $action){
    global $gCms;
 	  $userid = get_userid();
    $contentops =& $gCms->GetContentOperations();
  	$contentobj = $contentops->CreateNewContent('content');

  	$contentobj->SetOwner($userid);
  	$contentobj->SetCachable(1);
  	$contentobj->SetActive(1);
  	$contentobj->SetShowInMenu(0);
  	$contentobj->SetLastModifiedBy($userid);
  	$contentobj->SetPropertyValue('content_en', '<h1>'.$title.'</h1>'.'{cms_module module="'.$this->GetName().'" action="'.$action.'"}');
  	//if ($parent_id!=-1) $contentobj->SetParentId($parent_id);

    $contentobj->FillParams($params);

    $error = $contentobj->ValidateData();
		if ($error === FALSE){
  			$contentobj->Save();
  			global $gCms;
  			$contentops =& $gCms->GetContentOperations();
  			$contentops->SetAllHierarchyPositions();
  			audit($contentobj->Id(), $contentobj->Name(), 'Added Content by module '.$this->GetName());
    		return $contentobj->Id();
		};

		return false;
}









































}
?>
